/* Includes ------------------------------------------------------------------*/
#include "errorFlag.h"
#include <stddef.h>
/* typedef -------------------------------------------------------------------*/
/* define --------------------------------------------------------------------*/
/* macro ---------------------------------------------------------------------*/
#define ERRORFLAG_IS_TRIGGED(flag, index)           ((flag & (1<<index)) == (1<<index))
#define ERRORFLAG_IS_CLEARED(flag, index)           ((flag & (1<<index)) == 0)
#define ERRORFLAG_TRIGGER(flag, index)              {   flag |= (1<<index); }
#define ERRORFLAG_CLEAR(flag, index)                {   flag &= ~(1<<index); }

/* variables -----------------------------------------------------------------*/
/* function prototypes -------------------------------------------------------*/
/* functions -----------------------------------------------------------------*/
extern uint32_t NETimer_Get(void);
/*********************************************************************************************

  * @brief  ErrorFlag_Process
  * @param  error：the pointer of struct error obj
  * @return 
  * @remark 

  ********************************************************************************************/
void ErrorFlag_Process(struct ErrorFlag *error, void *param)
{
    uint32_t temp32u = 0, i, flagTrigged = 0, flagClear = 0;
  
    if(error->flag != error->__flagCache)
    {
        temp32u = error->flag ^ error->__flagCache;
        flagTrigged = temp32u & error->flag;
        flagClear = temp32u & (~error->flag);
        
        for(i=0; i<32; i++)
        {
            if((flagTrigged & (1<<i)) != 0)
            {
                if(error->event.trigger != NULL)
                {   error->event.trigger(error, i, param); }
            }
        }
        
        for(i=0; i<32; i++)
        {
            if((flagClear & (1<<i)) != 0)
            {
                if(error->event.clear != NULL)
                {   error->event.clear(error, i, param); }
            }
        }
        
        /* 更新标志位 */
        error->__flagCache = error->flag;
    }
}
/*********************************************************************************************

  * @brief  ErrorFlag_Trig
  * @param  error：the pointer of struct error obj
            index: the index of error
            parameter：the error param
  * @return 
  * @remark trig and run ErrorCheck_Handle immediately

  ********************************************************************************************/
void ErrorFlag_Trig(struct ErrorFlag *error, uint16_t index, void *param)
{
    ERRORFLAG_TRIGGER(error->flag, index);
    ErrorFlag_Process(error, param);   
}
/*********************************************************************************************

  * @brief  ErrorFlag_IsTriggered
  * @param  error：the pointer of struct error obj
            index: the index of error
  * @return 0: is not triggered
            1: is triggered
  * @remark 

  ********************************************************************************************/
inline bool ErrorFlag_IsTriggered(struct ErrorFlag *error, uint16_t index)
{   return ERRORFLAG_IS_TRIGGED(error->flag, index);  }
/*********************************************************************************************

  * @brief  ErrorFlag_Clear
  * @param  error：the pointer of struct error obj
            index: the index of error
            parameter：the error param
  * @return 
  * @remark 

  ********************************************************************************************/
void ErrorFlag_Clear(struct ErrorFlag *error, uint16_t index, void *param)
{
    ERRORFLAG_CLEAR(error->flag, index);
    ErrorFlag_Process(error, param);     
}
/*********************************************************************************************

  * @brief  ErrorFlag_IsCleared
  * @param  error：the pointer of struct error obj
            index: the index of error
  * @return 0: is not cleared
            1: is cleared
  * @remark 

  ********************************************************************************************/
inline bool ErrorFlag_IsCleared(struct ErrorFlag *error, uint16_t index)
{   return ERRORFLAG_IS_CLEARED(error->flag, index);  }

/*********************************************************************************************

    over threshold

********************************************************************************************/
void ErrorCheck_OverThreshold(struct ThresholdException *exception, 
							  int32_t value, 
							  int32_t threshold,
							  int32_t duration,
							  struct ErrorFlag *error, 
							  int32_t index,
							  uint32_t flag)
{
    if(ERRORFLAG_IS_TRIGGED(error->flag, index) == false)
    {
        if(exception->time == 0)
        {
            if(value > threshold)
            {    exception->time = NETimer_Get();    }
        }
        else
        {
            if(value < threshold)
            {   exception->time = 0;   }
            
            if(exception->time != 0 && (exception->time + duration) < NETimer_Get())
            {   
				if((flag & ERROR_FLAG_DELAY) != 0)
				{	ERRORFLAG_TRIGGER(error->flag, index);	}
				else
                {	ErrorFlag_Trig(error, index, &value); 	}
                exception->time = 0;
            }
        }
    }
    else
    {
        if(exception->time == 0)
        {
            if(value < threshold)
            {    exception->time = NETimer_Get();    }
        }
        else
        {
            if(value > threshold)
            {   exception->time = 0;   }
            
            if(exception->time != 0 && ((exception->time + duration) < NETimer_Get()))
            {   
				if((flag & ERROR_FLAG_DELAY) != 0)
                {	ERRORFLAG_CLEAR(error->flag, index); }
				else
				{	ErrorFlag_Clear(error, index, &value);	}
				
                exception->time = 0;
            }
        }
    }
}
/*********************************************************************************************

    lower threshold

********************************************************************************************/
void ErrorCheck_LowerThreshold(struct ThresholdException *exception, 
							  int32_t value, 
							  int32_t threshold,
							  int32_t duration,
							  struct ErrorFlag *error, 
							  int32_t index,
							  uint32_t flag)
{
    int thresholdLowerTemp = (threshold < 0)? ((threshold * 9) / 10):((threshold * 11) / 10);
    if(ERRORFLAG_IS_TRIGGED(error->flag, index) == false)
    {
        if(exception->time == 0)
        {
            if(value < threshold)
            {    exception->time = NETimer_Get();    }
        }
        else
        {
            if(value > threshold)
            {   exception->time = 0;   }
            
            if(exception->time != 0 && (exception->time + duration) < NETimer_Get())
            {   
                if((flag & ERROR_FLAG_DELAY) != 0)
				{	ERRORFLAG_TRIGGER(error->flag, index);	}
				else
                {	ErrorFlag_Trig(error, index, &value); 	} 
                exception->time = 0;
            }
        }
    }
    else
    {
        if(exception->time == 0)
        {
            if(value > thresholdLowerTemp)
            {    exception->time = NETimer_Get();    }
        }
        else
        {
            if(value < thresholdLowerTemp)
            {   exception->time = 0;   }
            
            if(exception->time != 0 && ((exception->time + duration) < NETimer_Get()))
            {   
                if((flag & ERROR_FLAG_DELAY) != 0)
                {	ERRORFLAG_CLEAR(error->flag, index); }
				else
				{	ErrorFlag_Clear(error, index, &value);	}
                exception->time = 0;
            }
        }
    }
}
/*********************************************************************************************

    lower or over threshold, not in range

********************************************************************************************/
void ErrorCheck_NotInThreshold(struct ThresholdException *exception, 
							  int32_t value, 
							  int32_t thresholdLower,
							  int32_t thresholdUpper,
							  int32_t duration,
							  struct ErrorFlag *error, 
							  int32_t index,
							  uint32_t flag)
{
    if(ERRORFLAG_IS_TRIGGED(error->flag, index) == false)
    {
        if(exception->time == 0)
        {
            if(value > thresholdUpper || value < thresholdLower)
            {    exception->time = NETimer_Get();    }
        }
        else
        {
            if(value < thresholdUpper && value > thresholdLower)
            {   exception->time = 0;   }
            
            if(exception->time != 0 && (exception->time + duration) < NETimer_Get())
            {   
                if((flag & ERROR_FLAG_DELAY) != 0)
				{	ERRORFLAG_TRIGGER(error->flag, index);	}
				else
                {	ErrorFlag_Trig(error, index, &value); 	} 
                exception->time = 0;
            }
        }
    }
    else
    {
        if(exception->time == 0)
        {
            if(value < thresholdUpper && value > thresholdLower)
            {    exception->time = NETimer_Get();    }
        }
        else
        {
            if(value > thresholdUpper || value < thresholdLower)
            {   exception->time = 0;   }
            
            if(exception->time != 0 && ((exception->time + duration) < NETimer_Get()))
            {   
                if((flag & ERROR_FLAG_DELAY) != 0)
                {	ERRORFLAG_CLEAR(error->flag, index); }
				else
				{	ErrorFlag_Clear(error, index, &value);	}
                exception->time = 0;
            }
        }
    }
}   

/*********************************************************************************************

    refresh not in time

********************************************************************************************/
void ErrorCheck_Stagnation(uint32_t time, 
						   uint32_t duration,
						   struct ErrorFlag *error, 
						   int32_t index,
						   uint32_t flag)
{
    
    if(ERRORFLAG_IS_TRIGGED(error->flag, index) == false)
    {
        if((time + duration) < NETimer_Get())
        {  
			if((flag & ERROR_FLAG_DELAY) != 0)
			{	ERRORFLAG_TRIGGER(error->flag, index);	}
			else
			{	ErrorFlag_Trig(error, index, NULL); 	} 
		}
    }
    else
    {
        if((time + 5) > NETimer_Get())
        {   
			if((flag & ERROR_FLAG_DELAY) != 0)
			{	ERRORFLAG_CLEAR(error->flag, index); }
			else
			{	ErrorFlag_Clear(error, index, NULL);	} 
		}
    }
}
/*********************************************************************************************

    count over threshold

********************************************************************************************/
void ErrorCheck_CountOver(uint32_t counter, 
                           uint32_t threshold,
                           struct ErrorFlag *error, 
                           int32_t index,
						   uint32_t flag)
{
    
    if(ERRORFLAG_IS_TRIGGED(error->flag, index) == false)
    {
        if(counter > threshold)
        {   
			if((flag & ERROR_FLAG_DELAY) != 0)
			{	ERRORFLAG_TRIGGER(error->flag, index);	}
			else
			{	ErrorFlag_Trig(error, index, NULL); 	} 
		}
    }
    else if(counter <= threshold)
    {
        if((flag & ERROR_FLAG_DELAY) != 0)
		{	ERRORFLAG_CLEAR(error->flag, index); }
		else
		{	ErrorFlag_Clear(error, index, NULL);	} 
    }
}
